home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Utilities / Magnify / Source / MagnifyView.m < prev    next >
Text File  |  1992-11-09  |  8KB  |  319 lines

  1. /* File: MagnifyView.m - View class for 'Magnify'
  2.  *
  3.  * By: Christopher Lane
  4.  * Symbolic Systems Resources Group
  5.  * Knowledge Systems Laboratory
  6.  * Stanford University
  7.  *
  8.  * Date:  9 November 1992
  9.  *
  10.  * Copyright: 1990, 1991 & 1992 by The Leland Stanford Junior University.
  11.  * This program may be distributed without restriction for non-commercial use.
  12.  */
  13.  
  14. #import "Magnify.h"
  15. #import "MagnifyView.h"
  16. #import "NXCursorPatch.h"
  17. #import "DefaultsTable.h"
  18.  
  19. #import <appkit/Pasteboard.h>
  20.  
  21. #define GRIDLINEMODE NX_COPY
  22. #define GRIDLINEWIDTH ((float) 1.0)
  23.  
  24. #define NX_CMYKMASK    (NX_MONOTONICMASK | NX_COLORMASK)
  25.  
  26. #define NX_EMPTYMASK (NX_COMMANDMASK & (~ NX_COMMANDMASK))
  27.  
  28. #define MAGNIFYLEVEL (100)
  29. #define NXSetWindowLevel _NXSetWindowLevel
  30. extern int NXSetWindowLevel(int, int);
  31.  
  32. @implementation MagnifyView
  33.  
  34. - initFrame:(const NXRect *) frameRect;
  35. {
  36.     [super initFrame:frameRect];
  37.  
  38.     frozen = NO;
  39.     lock = mutex_alloc();
  40.     flags = NX_EMPTYMASK;
  41.     mouse = frameRect->origin;
  42.     
  43.     scale = getFloatDefault("Scale");
  44.     showGrid = getBoolDefault("ShowGrid");
  45.     gridSize = getFloatDefault("GridSize");
  46.     showCursor = getBoolDefault("ShowCursor");
  47.  
  48.     return [self createWindows];
  49. }
  50.  
  51. - (BOOL) acceptsFirstResponder { return YES; }
  52.  
  53. - copy:sender
  54. {
  55.     char *buffer;
  56.     NXStream *stream;
  57.     int length, maxLength;
  58.     Pasteboard *pasteboard = [Pasteboard new];
  59.     
  60.     [pasteboard declareTypes:&NXPostScriptPboardType num:1 owner:self];
  61.  
  62.     stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  63.     [self copyPSCodeInside:&bounds to:stream];
  64.     NXFlush(stream);
  65.  
  66.     NXGetMemoryBuffer(stream, &buffer, &length, &maxLength);
  67.     [pasteboard writeType:NXPostScriptPboard data:buffer length:length];
  68.     NXCloseMemory(stream, NX_FREEBUFFER);
  69.         
  70.     return self;
  71. }
  72.  
  73. - drawSelf:(const NXRect *) rects :(int) rectCount
  74. {
  75.     mutex_lock(lock); {
  76.         NXDrawBitmap(&virtualBounds, pixelsWide, pixelsHigh, bitsPerSample, samplesPerPixel, bitsPerPixel, bytesPerRow, 
  77.             (BOOL) (planarConfig == NX_PLANAR),
  78.             (BOOL) ((photoInt & NX_ALPHAMASK) == NX_ALPHAMASK),
  79.             colorSpace, data);
  80.         if(showGrid) [self drawGrid];
  81.         if(showCursor) [self drawCursor];
  82.         } mutex_unlock(lock);
  83.  
  84.     return self;
  85. }
  86.  
  87. - free
  88. {
  89.     unsigned int i;
  90.     
  91.     if (invisibleWindow != nil) [invisibleWindow close];
  92.  
  93.     for(i = 0; i < NX_MAXPLANES; i++) if (data[i] != NULL) free(data[i]);
  94.     
  95.     return [super free];
  96. }
  97.  
  98. - sizeTo:(NXCoord) newWidth :(NXCoord) newHeight;
  99. {    
  100.     id result;
  101.     
  102.     mutex_lock(lock); {
  103.         result = [super sizeTo:newWidth :newHeight];
  104.         } mutex_unlock(lock);
  105.     
  106.     [self createWindows];
  107.     
  108.     return result;
  109. }
  110.  
  111. - mouseMoved:(NXEvent *)theEvent
  112. {
  113.     int eventMask;
  114.     
  115.     if (mutex_try_lock(lock)) {
  116.         eventMask = [window removeFromEventMask:NX_MOUSEMOVEDMASK]; {
  117.             while([NXApp peekAndGetNextEvent:NX_MOUSEMOVEDMASK] != NULL);
  118.  
  119.             mouse = theEvent->location;
  120.             [window convertBaseToScreen:&mouse];
  121.  
  122.             } [window setEventMask:eventMask];
  123.             
  124.         mutex_unlock(lock);
  125.             
  126.         [[self updateBitmap:&mouse] display];
  127.         }
  128.  
  129.     return [nextResponder mouseMoved:theEvent];
  130. }
  131.  
  132. - flagsChanged:(NXEvent *)theEvent
  133. {
  134.     flags = theEvent->flags;
  135.  
  136.     return [nextResponder flagsChanged:theEvent];
  137. }
  138.  
  139. - drawCursor
  140. {
  141.     NXSize size;
  142.     NXPoint point; 
  143.     NXImage *image;
  144.     NXCursor *cursor;
  145.     const NXPoint *hotSpot;
  146.     
  147.     if((cursor = [NXCursor currentCursor]) == nil) return nil;
  148.     
  149.     [(image = [cursor image]) getSize:&size];
  150.         
  151.     hotSpot = [cursor hotSpot];
  152.     
  153.     point.x = rint((bounds.size.width + scale) * HALF) - hotSpot->x; 
  154.     point.y = rint((bounds.size.height + scale) * HALF) - (size.height + hotSpot->y);
  155.  
  156.     [image composite:NX_SOVER toPoint:&point];
  157.  
  158.     return self;
  159. }
  160.  
  161. - drawGrid
  162. {    
  163.     float x, y, max;
  164.     
  165.     max = bounds.origin.y + bounds.size.height;
  166.     for(y = bounds.origin.y; y < max; y += gridSize)
  167.         PScompositerect(bounds.origin.x, y, bounds.size.width, GRIDLINEWIDTH, GRIDLINEMODE);
  168.         
  169.     max = bounds.origin.x + bounds.size.width;
  170.     for(x = bounds.origin.x; x < max; x += gridSize)
  171.         PScompositerect(x, bounds.origin.y, GRIDLINEWIDTH, bounds.size.height, GRIDLINEMODE);
  172.         
  173.     return self;
  174. }
  175.  
  176. - updateBitmap:(NXPoint *) point
  177. {
  178.     NXRect rect;
  179.     
  180.     mutex_lock(lock); {
  181.  
  182.         [invisibleView getFrame:&rect];
  183. #ifdef DEBUG
  184.         fprintf(stderr, "NXReadBitmap(rect:{%f,%f}, wide:%d, high:%d, bps:%d, spp:%d)\n",
  185.             rect.size.width, rect.size.height, pixelsWide, pixelsHigh, bitsPerSample, samplesPerPixel);
  186. #endif
  187.         [invisibleWindow moveTo:point->x - offset.width :point->y - offset.height];
  188.  
  189.         [invisibleWindow orderFront:self]; {
  190.             (void) [invisibleView lockFocus]; {
  191.                 NXReadBitmap(&rect, pixelsWide, pixelsHigh, bitsPerSample, samplesPerPixel, planarConfig, photoInt, data[0], data[1], data[2], data[3], data[4]);
  192.                 } [invisibleView unlockFocus];
  193.             } [invisibleWindow orderOut:self];
  194.     
  195.         } mutex_unlock(lock);
  196.     
  197.     bitsPerPixel = bitsPerSample * ((planarConfig == NX_PLANAR) ? 1 : samplesPerPixel);
  198.     bytesPerRow = (7 + pixelsWide * bitsPerSample * ((planarConfig == NX_PLANAR) ? 1 : samplesPerPixel)) / 8;
  199.     colorSpace = ((photoInt & NX_CMYKMASK) == NX_CMYKMASK) ? NX_CMYKColorSpace : (photoInt & NX_CMYKMASK);
  200.     
  201.     return self;
  202. }
  203.  
  204. - (int) flags { return flags; }
  205.  
  206. - (NXPoint *) mouse { return &mouse; }
  207.  
  208. - (float) scale { return scale; }
  209.  
  210. - setScale:(float) value
  211. {
  212.     mutex_lock(lock); {
  213.         scale = value;
  214.         } mutex_unlock(lock);
  215.     
  216.     return self;
  217. }
  218.  
  219. - (float) gridSize { return gridSize; }
  220.  
  221. - setGridSize:(float) value
  222. {
  223.     mutex_lock(lock); {
  224.         gridSize = value;
  225.         } mutex_unlock(lock);
  226.     
  227.     return self;
  228. }
  229.  
  230. - (BOOL) isFrozen { return frozen; }
  231.  
  232. - setFrozen:(BOOL) state
  233. {
  234.     mutex_lock(lock); {
  235.         if (frozen = state) (void) [window removeFromEventMask:NX_MOUSEMOVEDMASK];
  236.         else (void) [window addToEventMask:NX_MOUSEMOVEDMASK];
  237.         } mutex_unlock(lock);
  238.     
  239.     return self;
  240. }
  241.  
  242. - setShowGrid:(BOOL) state
  243. {
  244.     mutex_lock(lock); {
  245.         showGrid = state;
  246.         } mutex_unlock(lock);
  247.  
  248.     return [self display];
  249. }
  250.  
  251. - setShowCursor:(BOOL) state
  252. {
  253.     mutex_lock(lock); {
  254.         showCursor = state;
  255.         } mutex_unlock(lock);
  256.  
  257.     return [self display];
  258. }
  259.  
  260. - createWindows
  261. {
  262.     NXRect rect;
  263.     size_t size;
  264.     unsigned int i;
  265.     
  266.     mutex_lock(lock); {
  267.     
  268.         rect = bounds;
  269.         
  270.         offset.width = (rect.size.width = sizeof(int) * ceil((bounds.size.width / scale) / sizeof(int))) * HALF;
  271.         offset.height = (rect.size.height = ceil(bounds.size.height / scale)) * HALF;
  272.  
  273.         if (invisibleWindow != nil) [invisibleWindow sizeWindow:rect.size.width :rect.size.height];
  274.         else {
  275.             invisibleWindow = [[Window alloc] initContent:&rect style:NX_PLAINSTYLE backing:NX_NONRETAINED buttonMask:NX_NOBUTTONS defer:NO];
  276.             PSsetautofill(NO, [invisibleWindow windowNum]);
  277.             NXSetWindowLevel([invisibleWindow windowNum], MAGNIFYLEVEL);
  278.             [invisibleWindow setEventMask:NX_NULLEVENTMASK];
  279.             [(invisibleView = [invisibleWindow contentView]) allocateGState];
  280.             }
  281.  
  282.         [invisibleView getFrame:&rect];
  283.  
  284.         virtualBounds = rect;
  285.         virtualBounds.size.width *= scale;
  286.         virtualBounds.size.height *= scale;
  287.         
  288.         (void) [invisibleView lockFocus]; {
  289.             NXSizeBitmap(&rect, (int *) &size, &pixelsWide, &pixelsHigh, &bitsPerSample, &samplesPerPixel, &planarConfig, &photoInt);
  290.             } [invisibleView unlockFocus];
  291. #ifdef DEBUG
  292.         fprintf(stderr, "NXSizeBitmap(rect:{%f,%f}, wide:%d, high:%d, bps:%d, spp:%d)\n",
  293.             rect.size.width, rect.size.height, pixelsWide, pixelsHigh, bitsPerSample, samplesPerPixel);
  294. #endif
  295.         for(i = 0; i < NX_MAXPLANES; i++) {
  296.             if(data[i] == NULL) data[i] = malloc(size);
  297.             else if (size > malloc_size(data[i])) data[i] = realloc(data[i], size);
  298.             if(planarConfig == NX_MESHED) break;
  299.             }
  300.     
  301.         } mutex_unlock(lock);
  302.  
  303.     return [[self updateBitmap:&mouse] display];
  304. }
  305.  
  306. void timer(DPSTimedEntry teNumber, double now, id self)
  307. {
  308.     if (![self isFrozen]) {
  309.         NXPoint *mouse = [self mouse];
  310.         Window *window = [self window];
  311.         
  312.         [window getMouseLocation:mouse];
  313.         [window convertBaseToScreen:mouse];
  314.         [[self updateBitmap:mouse] display];
  315.         }
  316. }
  317.  
  318. @end
  319.